package com.mz361.stdapi.service.impl;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mz361.common.utils.CosUtil;
import com.mz361.common.utils.HttpServletUtil;
import com.mz361.common.utils.RedisUtil;
import com.mz361.common.utils.StringUtil;
import com.mz361.modules.system.domain.*;
import com.mz361.modules.system.service.*;
import com.mz361.stdapi.config.properties.APIProperties;
import com.mz361.stdapi.domain.*;
import com.mz361.stdapi.service.STDAPIService;
import com.mz361.stdapi.service.StandardPlanService;
import com.mz361.stdapi.service.StandardProfileService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Tuple;

import java.util.*;

/**
 * @author niceale
 * @ date 2024/04/26
 */
@Service
@Slf4j
public class STDAPIServiceImpl implements STDAPIService {

    private static final String standardClass_Url = "/api/v1/standardfClass";//分类接口地址
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    APIProperties apiProperties;
    @Autowired
    private CustNeedsService custNeedsService;
    @Autowired
    private PayOrderService payOrderService;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    private StandardPlanService standardPlanService;
    @Autowired
    private CMemberService cMemberService;
    @Autowired
    private CPackageService cPackageService;
    @Autowired
    private OrderUserService orderUserService;
    @Autowired
    private CosUtil cosUtil;
    @Autowired
    private StandardProfileService standardProfileService;

    /**
     * 标准分类
     *
     * @ return
     */
    @Override
    public JSONArray getStandardClass() {
        JSONArray jsonArray = null;
        //判断缓存中是否存在
        if (redisUtil.exists("STANDARD:CLASS")) {
            String value = redisUtil.getValue("STANDARD:CLASS");
            String newValue = value.replace("\"standardCode\":\"GB\"", "\"standardCode\":\"CN\"");
            jsonArray = JSONObject.parseArray(newValue);
        } else {
            String res = HttpServletUtil.sendGetRequestNoParams(apiProperties.getStdurl() + standardClass_Url, null);
            JSONObject jsonObject = JSONObject.parseObject(res);
            if (jsonObject.getInteger("code") == 200 && jsonObject.getJSONObject("data").getInteger("code") == 0) {
                jsonObject = jsonObject.getJSONObject("data");
                jsonArray = jsonObject.getJSONObject("data").getJSONArray("data");
                redisUtil.setValue("STANDARD:CLASS", jsonArray.toJSONString());
            }
        }
        //用于标准计划里面的分类名称筛选
        if (jsonArray != null) {
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject1 = jsonArray.getJSONObject(i);
                String code1 = jsonObject1.getString("standardCode");
                String name1 = jsonObject1.getString("standardName");
                if (jsonObject1.getBoolean("hasChild")) {
                    JSONArray jsonArray1 = jsonObject1.getJSONArray("child");
                    for (int n = 0; n < jsonArray1.size(); n++) {
                        JSONObject jsonObject2 = jsonArray1.getJSONObject(n);
                        String code2 = jsonObject2.getString("standardCode");
                        String name2 = jsonObject2.getString("standardName");
                        if (jsonObject2.getBoolean("hasChild")) {
                            JSONArray jsonArray2 = jsonObject2.getJSONArray("child");
                            for (int m = 0; m < jsonArray2.size(); m++) {
                                JSONObject jsonObject3 = jsonArray2.getJSONObject(m);
                                String code3 = jsonObject3.getString("standardCode");
                                String name3 = jsonObject3.getString("standardName");
                                if (jsonObject3.getBoolean("hasChild")) {
                                    JSONArray jsonArray3 = jsonObject3.getJSONArray("child");
                                    for (int s = 0; s < jsonArray3.size(); s++) {
                                        JSONObject jsonObject4 = jsonArray3.getJSONObject(s);
                                        String code4 = jsonObject4.getString("standardCode");
                                        String name4 = jsonObject4.getString("standardName");
                                        redisUtil.hSet("STANDARDPRESSPLAN:CLASS:" + code1 + ":FOURTH", code4, name4);
                                    }
                                }
                                redisUtil.hSet("STANDARDPRESSPLAN:CLASS:" + code1 + ":THIRD", code3, name3);
                            }
                        }
                        redisUtil.hSet("STANDARDPRESSPLAN:CLASS:" + code1 + ":SECOND", code2, name2);
                    }
                }
                redisUtil.hSet("STANDARDPRESSPLAN:CLASS", code1, name1);

            }
        }

        return jsonArray;

    }

    @Override
    public List<PlanClass> getPlanClass() {
        List<PlanClass> planClassList = new ArrayList<>();
        if (!redisUtil.exists("STANDARD:PLAN:CCSCOUNT")) {
            if (!redisUtil.exists("STANDARDPRESSPLAN:CLASS:ISO:SECOND")) {
                getStandardClass();//重新请求分类总数据
            }
            Set<String> keyList = redisUtil.hKeys("STANDARDPRESSPLAN:CLASS:ISO:SECOND");
            for (String field : keyList) {
                String name = redisUtil.hGet("STANDARDPRESSPLAN:CLASS:ISO:SECOND", field);
                Long total = standardPlanService.getStandardPlanLikeCcs(field);
                if (total > 0) {
                    PlanClass planClass = new PlanClass();
                    planClass.setStandardName(name);
                    planClass.setStandardCode(field);
                    planClass.setTotal(total);
                    planClassList.add(planClass);
                }
            }
            if (!planClassList.isEmpty()) {
                redisUtil.setexValue("STANDARD:PLAN:CCSCOUNT", 3600 * 24, JSONObject.toJSONString(planClassList));
            }
        } else {
            planClassList = JSONObject.parseArray(redisUtil.getValue("STANDARD:PLAN:CCSCOUNT"), PlanClass.class);
        }
        return planClassList;
    }

    @Override
    public Set<Tuple> searchHistory(String userId) {
        return redisUtil.getTopKeywords("SORT:STANDARDSEARCH:KEYWORD:" + userId, 10);

    }

    @Override
    public void clearHistory(String userId) {
        redisUtil.del("SORT:STANDARDSEARCH:KEYWORD:" + userId);
    }

    @Override
    public JSONObject fileURL(String userId, String standardNo) {
        JSONObject jsonObject = new JSONObject();
        String pdfPath = redisUtil.hGet("STANDARD:FILEPATH", StringUtil.md5(standardNo));
        // 首先检查文件路径是否存在
        if (StringUtil.isEmpty(pdfPath)) {
            jsonObject.put("flag", false);
            jsonObject.put("download", false);
            jsonObject.put("read", false);
            return jsonObject;
        }
        jsonObject.put("flag", true);

        // 处理标准编号中的特殊字符
        if (standardNo != null && StringUtil.isContans(standardNo, "&nbsp;")) {
            standardNo = standardNo.replace("&nbsp;", " ");
        }

        // 获取标准表格数据
        StandardTable standardTable = getStandardTable(standardNo);
        if (standardTable != null && standardTable.getFn_HavePDF().equals("0")) {//如果和ES中的文件标识不同步，则同步数据到ES
            ElasticsearchRestTemplate esTemplate = new ElasticsearchRestTemplate(restHighLevelClient);
            standardTable.setFn_HavePDF("1");
            esTemplate.save(standardTable);
        }

        // 检查是否为可直接下载的国标
        if (standardTable != null &&
                standardTable.getFn_StandClass().equals("CN") &&
                StringUtil.isEmpty(standardTable.getFn_AdoptNo())) {
            jsonObject.put("download", true);
            jsonObject.put("read", true);
            jsonObject.put("pdfpath", cosUtil.presignedUrl(pdfPath, null).toString());
            return jsonObject;
        }

        // 处理用户权限
        if (StringUtil.isEmpty(userId)) {
            jsonObject.put("download", false);
            jsonObject.put("read", false);
        } else {
            boolean result = checkDownLoadAndReadOnline(userId, standardNo, jsonObject);
            if (result) {
                jsonObject.put("pdfpath", cosUtil.presignedUrl(pdfPath, null).toString());
            }
        }
        return jsonObject;
    }

    @Override
    public String v2fileURL(String key, String standardNo) {
        if (standardNo != null && StringUtil.isContans(standardNo, "&nbsp;")) {
            standardNo = standardNo.replace("&nbsp;", " ");
        }
        String pdfpath = redisUtil.hGet("STANDARD:FILEPATH", StringUtil.md5(standardNo));
        if (StringUtil.notEmpty(pdfpath)) {
            return cosUtil.presignedUrl(pdfpath, "MANZHI").toString();
        }
        return null;
    }


    @Override
    public List<String> v2imageURLs(String standardNo, Integer start, Integer end) {
        if (standardNo != null && StringUtil.isContans(standardNo, "&nbsp;")) {
            standardNo = standardNo.replace("&nbsp;", " ");
        }
        String pdfpath = redisUtil.hGet("STANDARD:FILEPATH", StringUtil.md5(standardNo));
        if (StringUtil.notEmpty(pdfpath)) {
            return cosUtil.imageUrls(pdfpath, start, end);
        }
        return null;
    }

    @Override
    public boolean downLoadNotify(String userId, String standardNo, String title) {
        //下载标准排名记录
        redisUtil.incrementKeyword("SORT:STANDARDINFO:DOWNLOAD", standardNo + "|" + title);
        if (redisUtil.hexists("STANDARDINFO:DOWNLOAD:MZUNI", userId + "|" + standardNo)) {
            return true;
        }
        redisUtil.hSet("STANDARDINFO:DOWNLOAD:MZUNI", userId + "|" + standardNo, title);
        //判断是否非采标国标，不扣套餐次数
        StandardTable standardTable = getStandardTable(standardNo);
        if (standardTable != null && standardTable.getFn_StandClass().equals("CN") && StringUtil.isEmpty(standardTable.getFn_AdoptNo())) {
            return true;
        }
        CMember cMember = cMemberService.getById(Long.valueOf(userId));
        if (null != cMember) {
            // 检查用户是否已购买此标准
            PayOrder payOrder = payOrderService.getByStandardNoAndMemeberId(standardNo, cMember.getId());
            if (payOrder != null) {// 如果有购买记录，则不做任何处理，不走套餐逻辑
                return true;
            }

            List<OrderUser> orderUsers;
            String redisStr;
            if ("1".equals(cMember.getType())) {//个人用户
                orderUsers = orderUserService.getOrderUsersByMemeberIdAndServiceName(cMember.getId(), "下载");
                redisStr = "P:" + cMember.getId();//个人用户的Key
            } else {
                orderUsers = orderUserService.getOrderUsersByCompanyIdAndServiceName(cMember.getCompanyId(), "下载");
                redisStr = "Q:" + cMember.getCompanyId();//企业用户的Key
            }
            Long sumQuantity = 0L;
            for (OrderUser orderUser : orderUsers) {
                sumQuantity += orderUser.getQuantity();
            }
            if (sumQuantity == 0) {
                redisUtil.hSet("DOWNLOAD:ZERO", redisStr, "0");
                return false;
            }
            for (OrderUser orderUser : orderUsers) {
                if (orderUser.getQuantity() > 0) {
                    sumQuantity = sumQuantity - 1;
                    orderUser.setQuantity(orderUser.getQuantity() - 1);
                    orderUser.setUpdateDate(new Date());
                    orderUserService.save(orderUser);
                    if (sumQuantity == 0) {
                        //  当下载次数为0时，写入公司套餐下载次数为0
                        redisUtil.hSet("DOWNLOAD:ZERO", redisStr, "0");
                        return false;
                    }
                    break;//已经减掉一次了，跳出循环
                }
            }
        }
        return true;

    }

    @Override
    public boolean v2downLoadNotify(String key, String standardNo, String title) {
        return false;
    }

    @Override
    public boolean readOnLineNotify(String userId, String standardNo, String title) {
        //在线阅读排名数据记录
        redisUtil.incrementKeyword("SORT:STANDARDINFO:READONLINE", standardNo + "|" + title);
        if (redisUtil.hexists("STANDARDINFO:READONLINE:MZUNI", userId + "|" + standardNo)) {
            return true;
        }
        redisUtil.hSet("STANDARDINFO:READONLINE:MZUNI", userId + "|" + standardNo, title);
        //判断是否非采标国标，不扣套餐次数
        StandardTable standardTable = getStandardTable(standardNo);
        if (standardTable != null && standardTable.getFn_StandClass().equals("CN") && StringUtil.isEmpty(standardTable.getFn_AdoptNo())) {
            return true;
        }
        CMember cMember = cMemberService.getById(Long.valueOf(userId));
        if (null != cMember) {
            // 检查用户是否已购买此标准
            PayOrder payOrder = payOrderService.getByStandardNoAndMemeberId(standardNo, cMember.getId());
            if (payOrder != null) {// 如果有购买记录，则不做任何处理，不走套餐逻辑
                return true;
            }

            List<OrderUser> orderUsers;
            String redisStr;
            if ("1".equals(cMember.getType())) {//个人用户
                orderUsers = orderUserService.getOrderUsersByMemeberIdAndServiceName(cMember.getId(), "阅读");
                redisStr = "P:" + cMember.getId();//个人用户的Key
            } else {
                orderUsers = orderUserService.getOrderUsersByCompanyIdAndServiceName(cMember.getCompanyId(), "阅读");
                redisStr = "Q:" + cMember.getCompanyId();//企业用户的Key
            }
            Long sumQuantity = 0L;
            for (OrderUser orderUser : orderUsers) {
                sumQuantity += orderUser.getQuantity();
            }
            if (sumQuantity == 0) {
                //  当阅读次数为0时，写入公司套餐下载次数为0
                redisUtil.hSet("READ:ZERO", redisStr, "0");
                return false;
            }
            for (OrderUser orderUser : orderUsers) {
                if (orderUser.getQuantity() > 0) {
                    sumQuantity = sumQuantity - 1;
                    orderUser.setQuantity(orderUser.getQuantity() - 1);
                    orderUser.setUpdateDate(new Date());
                    orderUserService.save(orderUser);
                    if (sumQuantity == 0) {
                        //  当阅读次数为0时，写入公司套餐下载次数为0
                        redisUtil.hSet("READ:ZERO", redisStr, "0");
                        return false;
                    }
                    break;//已经减掉一次了，跳出循环
                }
            }
        }

        return true;
    }

    @Override
    public boolean v2readOnLineNotify(String key, String standardNo, String title) {
        return false;
    }

    @Override
    public UserPackageResult getUserPacakge(String userId) {
        CMember cMember = cMemberService.getById(Long.valueOf(userId));
        UserPackageResult userPackageResult;
        if (null != cMember) {
            userPackageResult = userPackageResult(cMember);
            return userPackageResult;
        }
        return null;
    }

    @Override
    public UserPackageResult v2getUserPacakge(String key) {
        return null;
    }

    @Override
    public PackagesResult getPackages(String userId) {
        PackagesResult packageResult = new PackagesResult();
        if (StringUtil.notEmpty(userId)) {
            CMember cMember = cMemberService.getById(Long.valueOf(userId));
            CSource cSource = cMember.getCsource();
            if (null != cSource) {
                packageResult.setCompanName(cSource.getName());
                List<CPackage> packages = cPackageService.getPackages();
                packages.forEach((item) -> {
                    item.setPrice((int) Math.round((double) (item.getPrice() * cSource.getDiscount()) / 100));
                });
                packageResult.setPackages(packages);
            } else {
                packageResult.setCompanName("官方平台");
                List<CPackage> packages = cPackageService.getPackages();
                packageResult.setPackages(packages);
            }

        } else {
            packageResult.setCompanName("官方平台");
            List<CPackage> packages = cPackageService.getPackages();
            packageResult.setPackages(packages);
        }
        return packageResult;
    }

    @Override
    public void custNeeds(String needs, String currentStatus, String conditionsProvided, String consultant, String consultUnit, String contact) {
        CustNeeds custNeeds = new CustNeeds();
        custNeeds.setNeeds(needs);
        custNeeds.setConditionsProvided(conditionsProvided);
        custNeeds.setBackgroundCurrentSituation(currentStatus);
        custNeeds.setConsultant(consultant);
        custNeeds.setConsultUnit(consultUnit);
        custNeeds.setContact(contact);
        custNeeds.setCreateDate(new Date());
        custNeedsService.save(custNeeds);

    }

    /**
     * 检测用户套餐情况
     *
     * @ param userId
     * @ param jsonObject
     */

    public boolean checkDownLoadAndReadOnline(String userId, String standardNo, JSONObject jsonObject) {
        // 初始化默认值
        jsonObject.put("download", false);
        jsonObject.put("read", false);

        // 检查用户是否存在
        CMember cMember = cMemberService.getById(Long.valueOf(userId));
        if (cMember == null) {
            return false;
        }

        // 检查用户是否已购买此标准
        PayOrder payOrder = payOrderService.getByStandardNoAndMemeberId(standardNo, cMember.getId());
        if (payOrder != null) {
            jsonObject.put("download", true);
            jsonObject.put("read", true);
            return true;
        }

        // 构建 Redis 键
        String redisKey = "1".equals(cMember.getType())
                ? "P:" + cMember.getId()
                : "Q:" + cMember.getCompanyId();

        // 获取用户套餐信息
        UserPackageResult userPackageResult = userPackageResult(cMember);
        boolean hasActivePackages = userPackageResult != null
                && userPackageResult.getProducts() != null
                && !userPackageResult.getProducts().isEmpty();

        if (!hasActivePackages) {
            return false;
        }

        // 检查下载权限
        boolean canDownload = !redisUtil.hexists("DOWNLOAD:ZERO", redisKey);
        jsonObject.put("download", canDownload);

        // 检查阅读权限
        boolean canRead = !redisUtil.hexists("READ:ZERO", redisKey);
        jsonObject.put("read", canRead);

        return canDownload || canRead;
    }

    public UserPackageResult userPackageResult(CMember cMember) {
        UserPackageResult userPackageResult = new UserPackageResult();
        List<OrderUser> orderUsers = null;
        if ("1".equals(cMember.getType())) {
            orderUsers = orderUserService.getOrderUsersByMemeberId(cMember.getId());
            userPackageResult.setCompanName(cMember.getName());
        } else if ("2".equals(cMember.getType())) {
            orderUsers = orderUserService.getOrderUsersByCompanyId(cMember.getCompanyId());
            userPackageResult.setCompanName(cMember.getCompany().getCompanyName());
        }
        List<ProductResult> productResults = new ArrayList<>();
        List<StandardDatas> standardDatas = new ArrayList<>();
        Map<String, List<PackageResult>> packageMap = new HashMap<>();
        Map<String, List<ServiceResult>> serviceMap = new HashMap<>();
        if (orderUsers != null) {
            for (OrderUser orderUser : orderUsers) {
                ProductResult productResult = new ProductResult();
                productResult.setName(orderUser.getProductName());
                // 判断是否已有此产品的套餐集合
                if (packageMap.get(orderUser.getProductName()) != null) {
                    //从Map中取出套餐集合
                    List<PackageResult> packageResults = packageMap.get(orderUser.getProductName());
                    PackageResult packageResult = new PackageResult();
                    packageResult.setName(orderUser.getPackageName());
                    //判断是否有此套餐的服务集合
                    if (serviceMap.get(orderUser.getProductName() + ":" + orderUser.getPackageName()) != null) {
                        List<ServiceResult> serviceResults = serviceMap.get(orderUser.getProductName() + ":" + orderUser.getPackageName());
                        ServiceResult serviceResult = new ServiceResult();
                        serviceResult.setName(orderUser.getCService().getName());
                        serviceResult.setQuantity(orderUser.getQuantity());
                        serviceResult.setUnit(orderUser.getUnit());
                        serviceResults.add(serviceResult);
                        packageResult.setServices(serviceResults);

                    } else {//没有此套餐的服务集合
                        List<ServiceResult> serviceResults = new ArrayList<>();
                        ServiceResult serviceResult = new ServiceResult();
                        serviceResult.setName(orderUser.getServiceName());
                        serviceResult.setQuantity(orderUser.getQuantity());
                        serviceResult.setUnit(orderUser.getUnit());
                        serviceResults.add(serviceResult);//将服务对象放入服务集合
                        packageResult.setServices(serviceResults);//将服务对象结合放入套餐对象
                        packageResults.add(packageResult);//将套餐对象放入套餐集合
                        serviceMap.put(orderUser.getProductName() + ":" + orderUser.getPackageName(), serviceResults);
                    }
                } else {//没有此产品的套餐信息
                    List<PackageResult> packageResults = new ArrayList<>();
                    List<ServiceResult> serviceResults = new ArrayList<>();
                    PackageResult packageResult = new PackageResult();
                    packageResult.setName(orderUser.getPackageName());
                    ServiceResult serviceResult = new ServiceResult();
                    serviceResult.setName(orderUser.getServiceName());
                    serviceResult.setQuantity(orderUser.getQuantity());
                    serviceResult.setUnit(orderUser.getUnit());
                    serviceResults.add(serviceResult);//将服务对象放入服务集合
                    packageResult.setServices(serviceResults);//将服务对象结合放入套餐对象
                    packageResults.add(packageResult);//将套餐对象放入套餐集合
                    productResult.setPacackages(packageResults);//将套餐集合放入产品对象
                    productResults.add(productResult);//将产品对象放入产品集合
                    serviceMap.put(orderUser.getProductName() + ":" + orderUser.getPackageName(), serviceResults);
                    packageMap.put(orderUser.getProductName(), packageResults);
                }

            }
        }

        List<PayOrder> payOrders = payOrderService.getByMemeberId(cMember.getId());
        payOrders.forEach(payOrder -> {
            StandardData standardData = standardProfileService.standardProfile(String.valueOf(cMember.getId()), payOrder.getPaidPackageTag());
            StandardDatas standardDatas1 = new StandardDatas();
            standardDatas1.setStandardNo(standardData.getStandardNo());
            standardDatas1.setTitle(standardData.getTitle());
            standardDatas1.setPrice((double) payOrder.getTotalFee() / 100);
            standardDatas.add(standardDatas1);
        });
        userPackageResult.setProducts(productResults);
        userPackageResult.setStandardDatas(standardDatas);
        return userPackageResult;

    }

    /**
     * 获取标准表格数据
     *
     * @param standardNo 标准编号
     * @return 标准表格数据
     */
    private StandardTable getStandardTable(String standardNo) {
        NativeSearchQueryBuilder query = new NativeSearchQueryBuilder();
        query.withQuery(QueryBuilders.matchPhraseQuery("fn_A100", standardNo));
        ElasticsearchRestTemplate restTemplate = new ElasticsearchRestTemplate(restHighLevelClient);
        SearchHits<StandardTable> hits = restTemplate.search(query.build(), StandardTable.class);
        for (SearchHit<StandardTable> searchHit : hits.getSearchHits()) {
            return searchHit.getContent();
        }
        return null;
    }
}
